﻿Friend Class RescanWorker
    Private Shared mWatchThread As Threading.Thread

    Public Shared Sub Start()
        If mWatchThread Is Nothing Then
            'register filesystem watchers
            Dim aWatches As Generic.List(Of Entities.SharedWatchFolder)
            aWatches = DataStore.SharedWatchFolders.GetAll

            For Each clsFolder As Entities.SharedWatchFolder In aWatches
                Try
                    Dim clsFSW As New System.IO.FileSystemWatcher(clsFolder.Path)
                    clsFSW.IncludeSubdirectories = clsFolder.Recursive
                    clsFSW.NotifyFilter = IO.NotifyFilters.LastWrite _
                                       Or IO.NotifyFilters.FileName _
                                       Or IO.NotifyFilters.DirectoryName
                    SetupEvents(clsFSW, True)
                    clsFSW.EnableRaisingEvents = True
                    mWatchers.Add(clsFSW)
                Catch ex As Exception
                    Manager.OnLogEvent(String.Format("Failed setting up file system watcher for ""{0}"": {1}", clsFolder.Path, ex.Message))
                End Try
            Next

            mWatchThread = New Threading.Thread(AddressOf WatchWorker)
            mWatchThread.Name = "File Watch Thread"
            mWatchThread.Priority = Threading.ThreadPriority.Lowest
            mWatchThread.Start()
        End If
    End Sub

    Public Shared Sub [Stop]()
        If mWatchThread IsNot Nothing Then
            mWatchThread.Abort()
            mWatchThread = Nothing

            For Each clsWatcher As IO.FileSystemWatcher In mWatchers
                clsWatcher.EnableRaisingEvents = False
                SetupEvents(clsWatcher, False)
            Next
            mWatchers.Clear()
        End If
    End Sub

    Private Shared Sub SetupEvents(ByVal watcher As IO.FileSystemWatcher, ByVal start As Boolean)
        If start Then
            AddHandler watcher.Renamed, AddressOf EventHandler_Renamed
            AddHandler watcher.Changed, AddressOf EventHandler_Changed
            AddHandler watcher.Created, AddressOf EventHandler_Created
            AddHandler watcher.Deleted, AddressOf EventHandler_Deleted
        Else
            RemoveHandler watcher.Renamed, AddressOf EventHandler_Renamed
            RemoveHandler watcher.Changed, AddressOf EventHandler_Changed
            RemoveHandler watcher.Created, AddressOf EventHandler_Created
            RemoveHandler watcher.Deleted, AddressOf EventHandler_Deleted
        End If
    End Sub

    Private Shared mWatchers As New Generic.List(Of IO.FileSystemWatcher)
    Private Shared Sub WatchWorker()
        Try
            'start by queuing a scan of all watched folders for changes that might have occured
            'while application wasn't running
            Try
                Dim aWatches As Generic.List(Of Entities.SharedWatchFolder)
                aWatches = DataStore.SharedWatchFolders.GetAll

                For Each clsShare As Entities.SharedWatchFolder In aWatches
                    RescanQueue.Queue(clsShare, clsShare.Path, TimeSpan.Zero)
                Next
            Catch ex As Exception
                Manager.OnLogEvent(String.Format("Error scanning folders: {0}", ex.Message), ex)
            End Try

            While True
                Try
                    Dim clsItem As RescanQueue.QueueItem = RescanQueue.GetNextItemToScan
                    If clsItem IsNot Nothing Then
                        Try
                            ScanFolder.ScanShareForChanges(clsItem.Share, clsItem.StartPath)
                        Catch ex As System.IO.IOException
                            Manager.OnLogEvent(String.Format("Error scanning share ""{0}"": {1}", clsItem.Share.Name, ex.Message), ex)
                            If clsItem.RetryCount < 30 Then
                                'requeue the item for later
                                RescanQueue.ReQueue(clsItem)
                            Else
                                Manager.OnLogEvent(String.Format("Gave up scanning share ""{0}"" after {1} failed attempts!", clsItem.StartPath, clsItem.RetryCount), ex)
                            End If
                        End Try
                    Else
                        Threading.Thread.Sleep(1000)
                    End If
                Catch ex As Threading.ThreadAbortException
                    Exit While
                Catch ex As Exception
                    Manager.OnLogEvent(String.Format("Error occured while scanning folder! {0}", ex.Message), ex)
                End Try
            End While
        Catch ex As Threading.ThreadAbortException
        Catch ex As Exception
            Manager.OnLogEvent(ex.Message, ex)
        End Try
    End Sub
    Private Shared Function FindShareByPath(ByVal path As String) As Entities.SharedWatchFolder
        For Each clsShare As Entities.SharedWatchFolder In DataStore.SharedWatchFolders.GetAll
            If Utils.IO.IsSubDir(path, clsShare.Path) Then
                Return clsShare
            End If
        Next
        Return Nothing
    End Function

    Private Shared Sub EventHandler_Renamed(ByVal sender As Object, ByVal e As IO.RenamedEventArgs)
        Try
            Dim clsShare As Entities.SharedWatchFolder = FindShareByPath(e.OldFullPath)
            RescanQueue.Queue(clsShare, IO.Path.GetDirectoryName(e.OldFullPath), TimeSpan.FromSeconds(10))
            If e.FullPath.ToLower <> e.OldFullPath.ToLower Then
                clsShare = FindShareByPath(e.FullPath)
                RescanQueue.Queue(clsShare, IO.Path.GetDirectoryName(e.FullPath), TimeSpan.FromSeconds(10))
            End If
        Catch ex As Exception
            Utils.Misc.HandleException(ex)
        End Try
    End Sub
    Private Shared Sub EventHandler_Changed(ByVal sender As Object, ByVal e As IO.FileSystemEventArgs)
        Try
            Dim clsShare As Entities.SharedWatchFolder = FindShareByPath(e.FullPath)
            RescanQueue.Queue(clsShare, IO.Path.GetDirectoryName(e.FullPath), TimeSpan.FromSeconds(10))
        Catch ex As Exception
            Utils.Misc.HandleException(ex)
        End Try
    End Sub
    Private Shared Sub EventHandler_Created(ByVal sender As Object, ByVal e As IO.FileSystemEventArgs)
        Try
            Dim clsShare As Entities.SharedWatchFolder = FindShareByPath(e.FullPath)
            RescanQueue.Queue(clsShare, IO.Path.GetDirectoryName(e.FullPath), TimeSpan.FromSeconds(10))
        Catch ex As Exception
            Utils.Misc.HandleException(ex)
        End Try
    End Sub
    Private Shared Sub EventHandler_Deleted(ByVal sender As Object, ByVal e As IO.FileSystemEventArgs)
        Try
            Dim clsShare As Entities.SharedWatchFolder = FindShareByPath(e.FullPath)
            RescanQueue.Queue(clsShare, IO.Path.GetDirectoryName(e.FullPath), TimeSpan.FromSeconds(10))
        Catch ex As Exception
            Utils.Misc.HandleException(ex)
        End Try
    End Sub

End Class
